package com.feeyo.prophet.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.feeyo.llm.agent.DecentralizedSSEAgent;

import com.feeyo.llm.agent.dialogue.DialogueAgent;
import com.feeyo.llm.agent.engine.*;


import com.feeyo.llm.api.chat.Chat;
import com.feeyo.llm.api.chat.Message;
import com.feeyo.llm.api.chat.azure.AzureImpl;
import com.feeyo.llm.api.chat.openai.CDN35Impl;
import com.feeyo.llm.util.ChatUtils;
import com.feeyo.llm.util.DateTimeUtil;
import com.feeyo.llm.util.JsonUtil;
import com.feeyo.llm.util.QuestionCategory;
import com.feeyo.prophet.actions.rcdi.FeeyoRcidAction;
import com.feeyo.prophet.plugins.*;
import com.feeyo.prophet.pojo.Conversation;
import com.feeyo.prophet.pojo.action.rcdi.BrainAnswerResp;
import com.feeyo.prophet.pojo.action.rcdi.FeeyoRcdiReq;
import com.feeyo.prophet.pojo.dto.ActionDTO;
import com.feeyo.prophet.pojo.dto.QuestionDTO;
import com.feeyo.prophet.pojo.enums.CategoryTypeEnum;
import com.feeyo.prophet.pojo.enums.ContentTypeEnum;
import com.feeyo.prophet.pojo.enums.RoleTypeEnum;
import com.feeyo.prophet.pojo.enums.UsefulnesEnum;
import com.feeyo.prophet.pojo.po.ChatRecord;
import com.feeyo.prophet.pojo.vo.AnswerVO;
import com.feeyo.prophet.pojo.vo.chart.BarChart;
import com.feeyo.prophet.pojo.vo.chart.Chart;
import com.google.common.collect.Lists;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;

@Slf4j
@Service
public class BrainV1Service {

    @Value("${openai.cdn.api.url}")
    private String apiUrl;

    @Value("${openai.cdn.api.key}")
    private String apiKey;

    @Value("${moonshot.key}")
    private String moonshotKey;


    @Value("${feeyo.current.prophet.host}")
    private String riakLocalHost;

    @Value("${feeyo.flightschedule.host}")
    private String scheduleHost;


    @Value("${prophet.model}")
    private String model;

    @Value("${feeyo.rcdi.port}")
    private int rcdiPort;

    @Value("${feeyo.rcdi.host}")
    private String rcdiHost;

    @Value("${openai.Azure.url}")
    private String azureUrl;

    @Value("${openai.Azure.apiKey}")
    private String azureApiKey;

    @Resource
    private MongoOperations mongoOperations;

    @Resource
    private AgentFactory agentFactory;
    /**
     * 存问题对
     */
    private final ChatRecordService chatRecordService;

    @Autowired
    public BrainV1Service(ChatRecordService chatRecordService) {
        this.chatRecordService = chatRecordService;
    }

    public void dialogue(String appId, String input, HttpServletRequest request, String conversationId, SseEmitter emitter, boolean isDebug) {
        Page<ChatRecord> records = chatRecordService.page(appId, conversationId, ConstantUtils.COMMON_INT_ZERO, ConstantUtils.COMMON_INT_TEN);
        List<Message> history = new ArrayList<>();
        String lastId = ConstantUtils.COMMON_STRING_ZERO;
        List<ChatRecord> content = records.getContent();
        for (int i = content.size() - 1; i >= 0; i--) {
            ChatRecord record = content.get(i);
            Integer type = record.getType();
            Message message;
            switch (RoleTypeEnum.valueOf(type)) {
                case USER:
                    message = Message.ofUser(record.getContent());
                    break;
                case SYSTEM:
                    message = Message.ofSystem(record.getContent());
                    break;
                case ASSISTANT:
                    message = Message.ofAssistant(record.getContent());
                    break;
                case null:
                default:
                    continue;
            }
            history.add(message);
            lastId = record.getId();
        }
        asyncAnswer(appId, input, request, lastId, history, conversationId, emitter, isDebug);
    }

    public static Map<String, String> questionCategory = new HashMap<>() {
        {
            put(CategoryTypeEnum.RCDI.getCode(), "民航法规和民航问题答疑。涉及到：航空安全、航空安保、航空运营管理、环境保护、乘客权利、国际航空法规、无人机和新兴航空技术、事故调查、机场管理、航空医疗领域。");
            put(CategoryTypeEnum.FLIGTH.getCode(), "航班问题。涉及到：航班动态、航班票价、航班统计等相关具体航班数据。");
            put(CategoryTypeEnum.FINANCE.getCode(), "财报问题。涉及到：机场财报、航司财报相关的具体数据。");
            put(CategoryTypeEnum.FLEET.getCode(), "机队问题。涉及到：机型、机号、机龄、承租人、出租人相关的具体数据。");
            put(CategoryTypeEnum.RANK.getCode(), "排名问题。涉及到：机场排名、航司排名、吞吐量排名");
            put(CategoryTypeEnum.BASIC.getCode(), "基础常识问题。涉及到：其他非民航领域问题。");
        }
    };

    public void asyncAnswer(String appId, String input, HttpServletRequest request, String lastId, List<Message> history, String conversationId, SseEmitter emitter, boolean isDebug) {
        ArrayList<String> follows = AgentFactory.getFollows();
        String id = Md5Util.generate();
        ChatRecord questionRecord = chatRecordService.insert(lastId, appId, conversationId, input, ContentTypeEnum.TEXT, "", RoleTypeEnum.USER.getCode());
        log.info(">>> processPush code:{} process:{}", ProcessEnum.CATEGORY.getCode(), ProcessEnum.CATEGORY.getDesc());
        String answerVO = JsonUtil.marshalToString(BrainAnswerResp.getBrainAnswerStep(ConstantUtils.COMMON_INT_ZERO, ProcessEnum.CATEGORY.getDesc()));
        DbSearchActionUtils.sseResponse(id, answerVO, lastId, emitter);
        DialogueAgent agent;
        Chat chat = new CDN35Impl(apiKey);
        chat = new AzureImpl(azureUrl, azureApiKey);

        try {
            QuestionCategory chatQueryCategory = ChatUtils.queryCategory(chat, model, history, input, questionCategory);
            //    chat = new FeeyoQwenImpl();
            agent = agentFactory.getDialogueAgent(conversationId, chat, model, apiKey, isDebug);
            String category = chatQueryCategory.getCategory();
            String language = chatQueryCategory.getLanguage();
            switch (CategoryTypeEnum.getTypeEnum(category)) {
                case RCDI:
                    rcdiAction(id, input, lastId, emitter, conversationId);
                    break;
//                case BASIC:
//                    basicAction(chat, history, input, id, appId, request, conversationId, emitter, questionRecord.getId());
//                    break;
//                case null:
                default:
                    scheduleAction(agent, follows, input, history, id, lastId, emitter, appId, request, conversationId, questionRecord, language, isDebug);
                    break;
            }
        } catch (Exception e) {

            ActionResult result = new ActionResult("\n\n\n\n" + ProcessEnum.DATA_ERROR.getDesc());
            if (isDebug) {
                result.setMsg(result.getMsg() + "\n\n" + e.getMessage());
            }
            doAnswer(id, result, appId, request, conversationId, emitter, "", ConstantUtils.COMMON_INT_ZERO);
            log.error("引擎初始化失败", e);
        }
    }

    private void scheduleAction(DialogueAgent agent, List<String> follows, String input, List<Message> history, String id, String lastId,
                                SseEmitter emitter, String appId, HttpServletRequest request, String conversationId, ChatRecord questionRecord, String language, boolean isDebug) throws Exception {
        List<String> nowFollows = new ArrayList<>(follows);
        nowFollows.add("现在的时间是：" + DateTimeUtil.yyyy_MM_ddHHmmssFormat(DateTimeUtil.currentTimeMillis()));

        ExecuteOptions executeOptions = new ExecuteOptions(nowFollows, ConstantUtils.COMMON_INT_TEN, true);
        executeOptions.setLanguage(language);
        agent.execute(input, history, executeOptions, new ExecuteListener() {
            final StringBuilder answer = new StringBuilder();
            final ActionResult actionResult = new ActionResult("");

            @Override
            public void onCompleted(ActionResult actionResult) {
                try {
                    log.info(">>> queryResult onCompleted msg:{}", JsonUtil.marshalToString(actionResult));
//                    if (CollectionUtils.isNotEmpty(actionResult.getAttachObjMap().values())) {
//                        doAnswer(id, actionResult, appId, request, conversationId, emitter, questionRecord.getId(), ConstantUtils.COMMON_INT_ZERO);
//                    }
                    //                  emitter.complete();
                } catch (Exception e) {

                } finally {
                    mongoOperations.upsert(
                            Query.query(Criteria.where("c_id").is(conversationId)),
                            Update.update("isRunning", "false"),
                            "prophet_chat"
                    );
                }
            }

            @Override
            public void onError(Throwable e) {
                try {
                    log.error(">>> onError:", e);
                    emitter.send(SseEmitter.event().data("小友暂时无法回答您的问题"));
                    request.setAttribute("handled", "handled");
                    emitter.complete();
                } catch (IOException ex) {

                    log.error("asyncQuery err", ex);
                } finally {
                    mongoOperations.upsert(
                            Query.query(Criteria.where("c_id").is(conversationId)),
                            Update.update("isRunning", "false"),
                            "prophet_chat"
                    );
                }
            }

            @Override
            public void onProgress(String q, String a) {
                // log.info(">>> onProgress appId:{} conversationId:{} q:{} a:{}", appId, conversationId, q, a);
            }

            @Override
            public synchronized void onSSEProgress(ProcessEnum code, String process) {
                log.debug(">>> processPush code:{} process:{}", code, process);
                if (ProcessEnum.DATA_COMPLETE == code) {
                    actionResult.setMsg(answer.toString());
                    doAnswer(id, actionResult, appId, request, conversationId, emitter, questionRecord.getId(), ConstantUtils.COMMON_INT_ONE);

                    mongoOperations.upsert(
                            Query.query(Criteria.where("c_id").is(conversationId)),
                            Update.update("isRunning", "false"),
                            "prophet_chat"
                    );
                    return;
                }
                if (ProcessEnum.SSE == code || code == ProcessEnum.ACTION_SSE || ProcessEnum.SSE_TIPS == code) {
                    String content = "";
                    try {
                        Conversation conversation = JSON.parseObject(process, Conversation.class);
                        if (conversation != null && CollectionUtils.isNotEmpty(conversation.getChoices())) {
                            content = conversation.getChoices().getFirst().getDelta().getContent();
                        }
                    } catch (Exception e) {
                        content = process;
                    }

                    if (StringUtils.isNotEmpty(content)) {
                        answer.append(content);
                        actionResult.setMsg(content);
                        doAnswer(id, actionResult, appId, request, conversationId, emitter, questionRecord.getId(), ConstantUtils.COMMON_INT_ZERO);
                    }
                } else if (ProcessEnum.SSE_URL == code) {
                    AttachObj attachObj = new AttachObj(AttachObj.Type.Chart, "图表数据查看", process);
                    ActionResult tmpResult = new ActionResult("");
                    tmpResult.putAttachObj(attachObj.getId(), attachObj);
                    doAnswer(id, tmpResult, appId, request, conversationId, emitter, questionRecord.getId(), ConstantUtils.COMMON_INT_ZERO);
//                } else if (ProcessEnum.SUMMARY == code || ProcessEnum.REFLECTION == code || ProcessEnum.CATEGORY == code || ProcessEnum.PLAN == code || ProcessEnum.SEARCH == code) {
//                    String answerVO = JsonUtil.marshalToString(BrainAnswerResp.getBrainAnswerStep(ConstantUtils.COMMON_INT_ZERO, code.getDesc()));
//                    DbSearchActionUtils.sseResponse(id, answerVO, lastId, emitter);
                } else if (ProcessEnum.DATA_ERROR == code) {
                    String msg = "";
                    if (!isDebug) {
                        msg = "小友暂时无法回答您的问题,请稍后再试";
                    } else {
                        msg = process;
                    }

                    String answerVO = JsonUtil.marshalToString(BrainAnswerResp.getBrainAnswerStep(ConstantUtils.COMMON_INT_ZERO, msg));
                    DbSearchActionUtils.sseResponse(id, answerVO, lastId, emitter);
                }
//                else {
//                    String answerVO = JsonUtil.marshalToString(BrainAnswerResp.getBrainAnswerStep(ConstantUtils.COMMON_INT_ZERO, process));
//                    DbSearchActionUtils.sseResponse(id, answerVO, lastId, emitter);
//                }
            }
        });
    }

    /**
     * 基础
     */
    private void basicAction(Chat chat, List<Message> history, String input, String id, String appId, HttpServletRequest request, String conversationId, SseEmitter emitter, String recordId) throws Exception {
        String simpleQuestion = ChatUtils.askSimpleQuestion(chat, model, history, input);
        ActionResult queryResult = new ActionResult("");
        if (StringUtils.isNotEmpty(simpleQuestion)) {
            queryResult.setMsg(simpleQuestion);
            doAnswer(id, queryResult, appId, request, conversationId, emitter, recordId, ConstantUtils.COMMON_INT_TWO);
        }
    }

    /**
     * rcdi 查询
     */
    private void rcdiAction(String id, String input, String lastId, SseEmitter emitter, String conversationId) {
        FeeyoRcidAction action = new FeeyoRcidAction(rcdiHost, rcdiPort);
        FeeyoRcdiReq req = new FeeyoRcdiReq();
        req.setQuestion(input);
        action.run(id, JSON.toJSONString(req), lastId, emitter, conversationId);
    }

    public void doAnswer(String id, ActionResult actionResult, String appId, HttpServletRequest request, String conversationId, SseEmitter emitter, String recordId, int type) {
        try {
            if (actionResult == null) {
                log.error(">>> onCompleted answer is null");
                return;
            }
            String answer = actionResult.getMsg();
            ContentTypeEnum contentTypeEnum = ContentTypeEnum.TEXT;
            List<AttachObj> attachObjList = new ArrayList<>(actionResult.getAttachObjMap().values());
            List<String> chartList = Lists.newArrayList();
            if (CollectionUtils.isNotEmpty(attachObjList)) {
                for (AttachObj attachObj : attachObjList) {
                    switch (attachObj.getType()) {
                        case AttachObj.Type.Link:
                            String link = attachObj.getValue().toString();
                            String description = attachObj.getDescription();
                            answer = answer + String.format("\n\n如需查看详细的全量数据，请点击以下链接：<a href=\"%s\" target=\"_blank\">%s</a>\n", link, description);
                            break;
                        case AttachObj.Type.Chart:
                            String linkUrl = attachObj.getValue().toString();
                            chartList.add(linkUrl);
                            break;
                    }
                }
            }
            // 做多图表兼容
            if (!chartList.isEmpty()) {
                contentTypeEnum = ContentTypeEnum.CHART;
                Chart chart = new Chart();
                chart.setAnswer(answer);
                chart.setData(chartList);
                answer = JSONObject.toJSONString(chart);
            }
            // 需要给answer 加一个type
            BrainAnswerResp brainAnswerResp = new BrainAnswerResp();
            brainAnswerResp.setPart(ConstantUtils.COMMON_INT_ONE);
            brainAnswerResp.setData(answer);
            String chatAnswer = JsonUtil.marshalToString(brainAnswerResp);
            ActionDTO actionDTO = new ActionDTO();
            actionDTO.setName(actionResult.getAction());
            JSONObject params = JSONObject.parseObject(actionResult.getInput());
            actionDTO.setParams(params);
            if (type == ConstantUtils.COMMON_INT_ZERO) {
                ChatRecord answerRecord = chatRecordService.assignment(recordId, appId, conversationId, chatAnswer, contentTypeEnum, actionDTO.toString(), RoleTypeEnum.ASSISTANT.getCode());
                AnswerVO answerVO = buildAnswer(params, actionResult.getAction(), answerRecord);
                answerVO.setId(id);
                String result = JSON.toJSONString(answerVO);
                DbSearchActionUtils.sseResponse(result, emitter);
            } else if (type == ConstantUtils.COMMON_INT_ONE) {
                chatRecordService.insert(recordId, appId, conversationId, chatAnswer, contentTypeEnum, actionDTO.toString(), RoleTypeEnum.ASSISTANT.getCode());
            } else {
                ChatRecord answerRecord = chatRecordService.insert(recordId, appId, conversationId, chatAnswer, contentTypeEnum, actionDTO.toString(), RoleTypeEnum.ASSISTANT.getCode());
                AnswerVO answerVO = buildAnswer(params, actionResult.getAction(), answerRecord);
                answerVO.setId(id);
                String result = JSON.toJSONString(answerVO);
                DbSearchActionUtils.sseResponse(result, emitter);
                // Handle completion
                String finishVo = JsonUtil.marshalToString(BrainAnswerResp.getBrainAnswerStep(ConstantUtils.COMMON_INT_TEN, ProcessEnum.DATA_COMPLETE.getDesc()));
                DbSearchActionUtils.sseResponse(id, finishVo, answerVO.getLastId(), emitter);
                log.info("SSE stream completed.");
                emitter.complete();
            }
        } catch (Exception e) {
            log.error("asyncQuery err appId:{} conversationId:{} result:{}", appId, conversationId, actionResult, e);
            try {
                AnswerVO answerVO = new AnswerVO();
                answerVO.setContent("小友暂时无法回答您的问题");
                answerVO.setContentType(ContentTypeEnum.TEXT.getCode());
                answerVO.setCreateTime(LocalDateTime.now());
                answerVO.setUsefulness(UsefulnesEnum.NON.getCode());
                emitter.send(SseEmitter.event().data(answerVO));
            } catch (IOException ignored) {
            }
            request.setAttribute("handled", "handled");
        }
    }

    @NotNull
    private static AnswerVO buildAnswer(JSONObject jsonObject, String action, ChatRecord answerRecord) {
        List<String> params = new ArrayList<>();
        if (null != jsonObject) {
            for (Map.Entry<String, Object> entry : jsonObject.entrySet()) {
                String key = entry.getKey();
                if ("language".equals(key)) {
                    continue;
                }
                if ("originalText".equals(key)) {
                    continue;
                }
                params.add(entry.getValue().toString());
            }
        }
        AnswerVO answerVO = AnswerVO.convert(answerRecord);
        answerVO.setParams(params);
        answerVO.setActions(action);
        return answerVO;
    }


    // ------------------- 历史版本 ------------------------
    public void dialogue(String appId, QuestionDTO questionDTO, HttpServletRequest request, String conversationId, SseEmitter emitter) {
        Page<ChatRecord> records = chatRecordService.page(appId, conversationId, 0, 10);
        List<Message> history = new ArrayList<>();
        String lastId = "0";
        List<ChatRecord> content = records.getContent();
        for (int i = content.size() - 1; i >= 0; i--) {
            ChatRecord record = content.get(i);
            Integer type = record.getType();
            Message message;
            if (Objects.equals(RoleTypeEnum.USER.getCode(), type)) {
                message = Message.ofUser(record.getContent());
            } else if (Objects.equals(RoleTypeEnum.SYSTEM.getCode(), type)) {
                message = Message.ofSystem(record.getContent());
            } else if (Objects.equals(RoleTypeEnum.ASSISTANT.getCode(), type)) {
                message = Message.ofAssistant(record.getContent());
            } else {
                continue;
            }
            history.add(message);
            lastId = record.getId();
        }
        asyncAnswer(appId, questionDTO, request, lastId, history, conversationId, emitter);
    }

    public void asyncAnswer(String appId, QuestionDTO questionDTO, HttpServletRequest request, String lastId, List<Message> history, String conversationId, SseEmitter emitter) {
        ArrayList<String> follows = new ArrayList<>() {{
            this.add("当前国家是中国");
            this.add("不要向用户询问 问题中使用到的IATA中的如国家二字码, 城市三字码, 机场三字码等");
            this.add("注意有些IATA城市三字码和IATA机场三字码是不同的");
            this.add("国外代表中国以外的所有多个国家, 国内代表中国大陆, 地区代表中国港澳台");
            this.add("航班的单位用\"班\", 不要用\"次\"");
            this.add("询问涉及到的具体的日期范围,如果没有提供,就默认7天");
            this.add("回答问题必须包含问题中的所有重要条件, 不可缺漏.");
            this.add("问题中包含变化趋势的内容,需要对日期按照语义维度进行拆分,并且用拆分的日期进行遍历查询");
            this.add("回答问题如果有条件不支持必须说明。");
            this.add("如果问题没给具体开始时间，那么默认开始时间是2019年");
        }};
        String input = questionDTO.getInput();
        DecentralizedSSEAgent agent = null;
        Chat chat = new AzureImpl(azureUrl, azureApiKey);
        String category = "";
        String language = "中文";
        try {
            agent = agentFactory.getDecentralizedSSEAgent(conversationId, chat, model, false);
            //问题分类
            QuestionCategory queriedCategory = ChatUtils.queryCategory(chat, model, history, input, questionCategory);
            category = queriedCategory.getCategory();
            language = queriedCategory.getLanguage();
        } catch (Exception e) {
            log.error("引擎初始化失败", e);
        }
        if (CategoryTypeEnum.BASIC.getCode().equals(category)) {
            try {
                String simpleQuestion = ChatUtils.askSimpleQuestion(chat, model, history, input);
                if (StringUtils.isNotEmpty(simpleQuestion)) {
                    ActionResult queryResult = new ActionResult(simpleQuestion);
                    doAnswer(queryResult, appId, request, lastId, input, conversationId, emitter);
                }
            } catch (Exception e) {
                log.error(">>> askSimpleQuestion err", e);
            }
        } else {
            assert agent != null;
            try {
                agent.execute(input, history, ExecuteOptions.ofSSE(10), new ExecuteListener() {
                    final StringBuilder answer = new StringBuilder();

                    @Override
                    public void onCompleted(ActionResult queryResult) {

                        queryResult.setMsg(answer.toString());
                        log.info(">>> onCompleted result:{}", JsonUtil.marshalToString(queryResult));
                        doAnswer(queryResult, appId, request, lastId, input, conversationId, emitter);
                    }

                    @Override
                    public void onError(Throwable e) {
                        try {
                            log.error(">>> onError:", e);
                            emitter.send(SseEmitter.event().data("小友暂时无法回答您的问题"));
                            request.setAttribute("handled", "handled");
                            emitter.complete();
                        } catch (IOException ex) {
                            log.error("asyncQuery err", ex);
                        }
                    }

                    @Override
                    public void onProgress(String q, String a) {
                        log.info(">>> onProgress appId:{} conversationId:{} q:{} a:{}", appId, conversationId, q, a);
                    }

                    @Override
                    public void onSSEProgress(ProcessEnum code, String process) {
                        log.debug(">>> processPush code:{} process:{}", code, process);
                        if (ProcessEnum.SSE == code) {
                            try {
                                Conversation conversation = JSON.parseObject(process, Conversation.class);
                                if (conversation != null && CollectionUtils.isNotEmpty(conversation.getChoices())) {
                                    String content = conversation.getChoices().getFirst().getDelta().getContent();
                                    if (StringUtils.isNotEmpty(content)) {
                                        answer.append(content);
                                    }
                                }
                            } catch (Exception ignored) {
                            }
                        }
                    }
                });
            } catch (Exception e) {
                log.error(">>>  DecentralizedAgent err", e);
            }
        }
    }

    public void doAnswer(ActionResult queryResult, String appId, HttpServletRequest request, String lastId, String input, String conversationId, SseEmitter emitter) {
        boolean isEmitterCompleted = false;
        try {
            String answer = queryResult.getMsg();
            ContentTypeEnum contentTypeEnum = ContentTypeEnum.TEXT;
            List<AttachObj> attachObjList = new ArrayList<>(queryResult.getAttachObjMap().values());
            if (CollectionUtils.isNotEmpty(attachObjList)) {
                for (int i = 0; i < attachObjList.size(); i++) {
                    AttachObj attachObj = attachObjList.get(i);
                    switch (attachObj.getType()) {
                        case AttachObj.Type.Link:
                            String link = attachObj.getValue().toString();
                            String description = attachObj.getDescription();
                            contentTypeEnum = ContentTypeEnum.TEXT;
                            answer = answer + String.format("\n\n如需查看详细的全量数据，请点击以下链接：[%s](%s)", description, link);
                            break;
                        case AttachObj.Type.Chart:
                            Object attach = attachObj.getValue();
                            if (attach instanceof BarChart barChart) {
                                contentTypeEnum = ContentTypeEnum.CHART;
                                barChart.setAnswer(answer);
                                answer = JSONObject.toJSONString(barChart);
                            }
                            break;
                    }
                }
            }
            ChatRecord questionRecord = chatRecordService.insert(lastId, appId, conversationId, input, contentTypeEnum, "", RoleTypeEnum.USER.getCode());
            ActionDTO actionDTO = new ActionDTO();
            actionDTO.setName(queryResult.getAction());
            JSONObject params = JSONObject.parseObject(queryResult.getInput());
            actionDTO.setParams(params);
            ChatRecord answerRecord = chatRecordService.insert(questionRecord.getId(), appId, conversationId, answer, contentTypeEnum, actionDTO.toString(), RoleTypeEnum.ASSISTANT.getCode());
            AnswerVO answerVO = buildAnswer(params, queryResult.getAction(), answerRecord);
            String result = JSONObject.toJSONString(answerVO);
            // 检查是否已经完成
            if (!isEmitterCompleted) {
                try {
                    emitter.send(SseEmitter.event().data(result));
                    log.info(">>>> doAnswer appId:{} conversationId:{} result:{}", appId, conversationId, result);
                    request.setAttribute("handled", "handled");
                } catch (IOException e) {
                    log.error("Error sending data through emitter", e);
                    isEmitterCompleted = true;
                }
            }
        } catch (Exception e) {
            log.error("asyncQuery err appId:{} conversationId:{} result:{}", appId, conversationId, queryResult, e);
            if (!isEmitterCompleted) {
                try {
                    AnswerVO answerVO = new AnswerVO();
                    answerVO.setContent("小友暂时无法回答您的问题");
                    answerVO.setContentType(ContentTypeEnum.TEXT.getCode());
                    answerVO.setCreateTime(LocalDateTime.now());
                    answerVO.setUsefulness(UsefulnesEnum.NON.getCode());
                    emitter.send(SseEmitter.event().data(answerVO));
                } catch (IOException ignored) {
                    isEmitterCompleted = true;
                }
            }
            request.setAttribute("handled", "handled");
        } finally {
            if (!isEmitterCompleted) {
                emitter.complete();
            }
        }
    }

}